home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
asmbler.arc
/
NEWCTLT.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-11-19
|
15KB
|
447 lines
title CTLT - Control-T Interrupt Handler
page 60,132
;***********************************************************************
;
; This routine works by trapping every interrupt 9 (KB_INT) generated by
; the keyboard and handled by the IBM BIOS, and after return from BIOS,
; inspecting the key which was typed and is now present in the keyboard
; ring buffer in the BIOS data segment (40h). If it is the user
; interrupt character (normally a CTL-T), it is removed from the buffer
; and a status message is displayed on the console screen.
;
; ***************
; *** N O T E ***
; ***************
;
; This code depends upon buffer size, organization, and location, and
; pointers thereto, in the IBM BIOS data segment. If a different
; keyboard interrupt handler is installed (e.g. one that increases
; buffer size), this code will probably fail!
;
; [02-Aug-84] Nelson H.F. Beebe, College of Science Computer,
; University of Utah, Salt Lake City, UT 84112, USA
;***********************************************************************
.xlist
include ascii.inc
include dos.inc
.list
keyvect segment at 0
org 9h*4 ; BIOS KB_INT
keyint label dword
keyvect ends
biosdata segment at 40h
org 1ah ; See p. A-3 of IBM Tech. Ref. Manual
buffer_head dw ? ; pointer to head of keyboard buffer
; -- address of first available char
buffer_tail dw ? ; pointer to tail of keyboard buffer
; -- address of next empty slot
; -- buffer is empty if head=tail
kb_buffer dw 16 dup (?) ; room for 15 entries
org $-2
kb_bufend dw ? ; last word in buffer
biosdata ends
;***********************************************************************
;
; INIT_CODE - Code to load and initialize the handler.
; Sets up DOS to keep all code before "LASTONE" label safe from
; overlaying during system operation.
;
;***********************************************************************
CODE SEGMENT PARA
org 100h ; for .COM file
assume cs:code,ds:code
assume es:biosdata
TYPE_CHAR PROC NEAR
; Type character in AL at the current cursor position using the current
; character attribute. No translation is done, except that BIOS handles
; CR, LF, BEL, and BS as for a teletype.
; All registers preserved
push ax
push bx
push ax ; save extra copy of character
mov ah,$VIDEO_GETVIDEOSTATE
int $VIDEO ; get current page in bh
mov ah,$VIDEO_GETATTRCHAR
int $VIDEO ; get current attribute in ah
mov bl,ah ; save current attribute
pop ax ; restore character
mov ah,$VIDEO_SETTTY ; tty output (bl = current attribute)
int $VIDEO ; character
pop bx ; restore registers
pop ax
ret
TYPE_CHAR ENDP
assume cs:code,ds:code
TYPE_CRLF PROC NEAR
; Type CR LF pair
; All registers preserved
push ax ; save registers
mov al,.CR
call TYPE_CHAR
mov al,.LF
call TYPE_CHAR
pop ax ; restore registers
ret
TYPE_CRLF ENDP
assume cs:code,ds:code
TYPE_DEC PROC NEAR
; Type integer in AX in decimal, BH = fill character, BL = field width
; BL=0 means minimum field width with no fill
; All registers preserved
push ax ; save registers
push bx
push cx
push dx
push bp
xor cx,cx
mov cl,bl ; minimum field width
mov bp,ax ; save original number
test ax,ax ; number < 0?
jge not_neg ; no
neg ax ; yes, replace by abs(number)
not_neg:
push EFLAG ; mark end of number on stack
digit_loop:
cwd ; sign-extend ax into (ax,dx)
dec cx ; reduce field width
div TEN ; number/10 to ax, remainder to dx
add dx,"0" ; convert to ASCII
push dx ; save digit
test ax,ax ; zero yet?
ja digit_loop ; no, keep dividing
mov dx,bp ; original number
test dx,dx ; number < 0?
jge digit_plus ; no
dec cx ; yes, reduce field width
cmp bh," " ; blank fill?
jne digit_plus ; no
mov al,"-" ; yes, save immediate leading
push ax ; minus sign
digit_plus:
test cx,cx ; remaining count > 0?
jle digit_sign ; yes, fill unnecessary
mov al,bh ; fill character
digit_fill:
push ax ; save fill character
loop digit_fill ; loop until cx=0
digit_sign:
mov dx,bp ; original number
test dx,dx ; number < 0?
jge digit_type ; no
cmp bh," " ; blank fill?
je digit_type ; yes, already saved sign
mov al,"-" ; no, save sign
push ax
digit_type:
pop ax ; digit
cmp ax,EFLAG ; end of number yet?
je digit_done ; yes
call TYPE_CHAR ; type it
jmp short digit_type ; and go for next digit
digit_done:
pop bp ; restore registers
pop dx
pop cx
pop bx
pop ax
ret ; return to caller
EFLAG dw -1 ; special end-of-number flag
TEN dw 10
TYPE_DEC ENDP
assume cs:code,ds:code
TYPE_HEX PROC NEAR
; Type byte in AL as two-character hexadecimal
; All registers preserved
push cx ; save registers
push bx
push ax
push ax ; save ax
mov bh,0 ; clear top of bx
mov cl,4 ; shift count
mov bl,al ; byte to print
shr bl,cl ; left nibble
mov al,hex_chars[bx]; get character
call TYPE_CHAR ; and print it
pop bx ; restore ax into bx
and bx,0fh ; left nibble
mov al,hex_chars[bx]; get character
call TYPE_CHAR ; and print it
pop ax ; restore registers
pop bx
pop cx
ret
hex_chars db "0123456789ABCDEF"
TYPE_HEX ENDP
assume cs:code,ds:code
TYPE_STRING PROC NEAR
; Type NUL-terminated string pointed to by DS:SI (the NUL is not typed).
; All registers preserved
push ax
push dx
push si
cld ; read string forward
msg_loop:
lodsb ; byte to al, increment si
test al,al ; message byte = 0?
jz done_string ; yes, all done
call TYPE_CHAR ; no, type it
jmp short msg_loop ; keep printing
done_string:
pop si
pop dx
pop ax
ret
TYPE_STRING ENDP
assume cs:code,ds:code
TYPE_TIME PROC NEAR
; Type the current time as hh:mm:ss
; All registers preserved
push ax ; save registers
push bx
push cx
push dx
mov ah,$DOS_GETTIME
int $DOS
xor ah,ah ; clear top of ax
mov al,ch ; hours
mov bl,0 ; field width=0
mov bh," " ; fill character
call TYPE_DEC ; type hh
mov al,":"
call TYPE_CHAR
mov al,cl ; minutes
mov bl,2 ; field width
mov bh," " ; fill character
call TYPE_DEC ; type mm
mov al,":"
call TYPE_CHAR
mov al,dh ; seconds
mov bl,2 ; field width
mov bh," " ; fill character
call TYPE_DEC ; type ss
mov al,"."
call TYPE_CHAR
mov al,dl ; centiseconds
mov bl,2 ; field width
mov bh," " ; fill character
call TYPE_DEC ; now have typed "hh:mm:ss.cc"
pop dx ; restore registers
pop cx
pop bx
pop ax
ret ; return to caller
TYPE_TIME ENDP
assume cs:code,ds:code
assume es:biosdata
KEY PROC NEAR
start:
jmp init_code ; done only once at startup
key_call: ; Far JMP to keyboard interrupt
jmp far ptr es:0 ; filled in at runtime
; db 0eah
; dw 0,0
old_ip equ [bp+2] ; bp = entry_sp-2
old_cs equ [bp+4]
old_fl equ [bp+6]
key_rtne:
sti ; turn interrupts back on
push ax ; save registers
push bx
push cx
push dx
push bp
push ds
push es
push di
push si
mov bx,cs
mov ds,bx ; establish local DS = CS
mov bx,biosdata
mov es,bx ; establish ES -> BIOSDATA
; First call original KB_INT BIOS code to actually retrieve the character
; over the keyboard port and do its massive amount of bookkeeping
pushf ; flags to fake interrupt call
mov bx,offset key_call+1 ; get address of ROM code for keyboard
call dword ptr [bx] ; call ROM code
;-----------------------------------------------------------------------
; enter critical section -- no interrupts allowed until character retrieved
; and buffer pointers updated
cli ; interrupts off while char retrieved
mov bx,es:buffer_tail ; next available slot in buffer
dec bx ; backup 2 bytes
dec bx
cmp bx,offset kb_buffer ; backed up before start?
jae nowrap ; no
mov bx,offset kb_bufend ; yes, move to end of buffer
nowrap:
mov ax,es:[bx] ; char in al, scan code in ah
cmp al,.ctlt ; CTL-T?
jne done ; no
mov es:buffer_tail,bx ; remove last character (the CTL-T)
sti ; interrupts back on
; end critical section
;-----------------------------------------------------------------------
call TYPE_TIME
mov si,offset csip_msg
call TYPE_STRING
mov al,old_cs+1
call TYPE_HEX
mov al,old_cs
call TYPE_HEX
mov al,":"
call TYPE_CHAR
mov al,old_ip+1
call TYPE_HEX
mov al,old_ip
call TYPE_HEX
mov si,offset flags_msg
call TYPE_STRING
mov al,old_fl+1
call TYPE_HEX
mov al,old_fl
call TYPE_HEX
call TYPE_CRLF
done_int:
pop si ; restore saved registers
pop di
pop es
pop ds
pop bp
pop dx
pop cx
pop bx
pop ax
iret ; return from interrupt
csip_msg db " CS:IP ",0
flags_msg db " Flags ",0
KEY ENDP
lastone: ; all code after this label is freed to DOS after
; program initialization
copyrt db 'CONTROL-T Handler -- Version 1.0 -- Public Domain 1984'
db .CR,.LF
db 'Nelson H.F. Beebe, University of Utah, Salt Lake City, '
db 'UT 84112, USA'
db .CR,.LF,0
assume cs:code,ds:code
assume es:keyvect
INIT_CODE PROC NEAR
; Initialize KEYBOARD interrupt system
;-----------------------------------------------------------------------
; enter critical section -- no interrupts while adjusting interrupt vector
;
cli ; interrupts off
mov ax,keyvect ; Get address to interrupt vector
mov es,ax ; Save in ES
mov ax,es:keyint ; Get address to interrupt routine
mov bx,offset key_call+1 ; Address to place to save vector
mov [bx],ax ; Save interrupt address
mov ax,es:keyint[2] ; Get interrupt segment for routine
mov [bx+2],ax ; Save it too
mov es:keyint,offset key_rtne ; Now, replace with own address
mov ax,cs ; Save segment in interrupt vector
mov es:keyint[2],ax
sti ; interrupts back on
; end critical section
;-----------------------------------------------------------------------
; Now, print out acknowledgement to user monitor and exit
mov ax,cs ; Set up segment to this routine
mov ds,ax
mov si,offset copyrt ; Now, print out copyright message
call TYPE_STRING
mov dx,offset lastone ; Save all code up to "LASTONE" label
int 27h ; No return needed
INIT_CODE ENDP
CODE ENDS
END START